home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-22 | 14.6 KB | 489 lines | [TEXT/RLAB] |
- FUNCTION:
-
- This help file covers several aspects of functions:
-
- 1) Introduction
-
- 2) Variable scoping
-
- 3) Function arguments
-
- 4) Function return values
-
- 5) Function recursion
-
- 6) Special topics
-
- 1) Introduction ------------------------------------------------
-
- Functions are an essential part of the language. Learning how
- to create and use functions will greatly add to the benefits
- of using RLaB.
-
- It is important to remember that functions adhere to the RLaB
- rule: "everything is a variable". Functions are variables, and
- like the other types or classes of variables in RLaB can be
- printed (although it will be hard to understand the output),
- copied, and renamed. Functions cannot act as operands to
- numeric operators, although the result of the function usually
- can. Since function calls are evaluated "in-place" they can be
- used within other expressions, for example:
-
- > sin(cos(1.0))
- 0.514
-
- > sin( [ cos(0.3), sqrt(cos(0.3)) ] )
- 0.817 0.829
-
-
- The syntax used for function definition is a little unusual...
-
- Example:
-
- > sum = function (s)
- {
- local(i, Sum);
- Sum = 0;
- for(i in 1:size(s)) {
- Sum = Sum + s[i];
- }
- return Sum;
- };
- >
-
- creates a function, and assigns it to the variable `sum'.
- Sum is invoked like:
-
- > sum( [1,2,3,4,5] )
- 15
-
- 2) Variable Scopes ---------------------------------------------
-
- When you start a RLaB session, either interactively or in
- batch-mode, you create an environment. The environment or
- workspace consists of the built-in functions, and any other
- variables or functions you may have added. The workspace will
- also be referred to as the global-symbol-table or the global
- scope.
-
- There are two other types of environment available: a
- function's local environment and a file's static environment
- (we will use the term environment and scope interchangeably).
-
- A function's local scope is temporary, it is created when the
- function is invoked, and is destroyed when the function
- returns. A file's static scope is created when the file is
- loaded, and remains intact until the RLaB session is
- terminated.
-
- The different scopes serve to protect data from operations
- that occur in the other scopes. There is some degree of
- overlap in order to allow flexibility. Functions can affect
- file-static and global scopes; statements within files can
- affect statements within other files and the global
- scope. More simply put, the "lower" scopes generally have
- access to the "higher" scopes. When a variable is used, RLaB
- uses certain rules to "bind" the variable. When we use the
- term bind or bound, we mean that the variable name is
- associated with an entry in one of the three types of symbol
- tables.
-
- File-Scope: Variables that are in a file (but not within a
- function) are bound to the global-symbol-table
- (global-scope or global-environment) unless a
- static declaration is used. When a variable is
- declared static (see `help static') it is bound to
- the file's symbol table. From that point on, the
- variable will remain bound to the file's
- scope. When a variable is declared static, it is
- not visible from the global environment or from
- any other files.
-
- Function Local Scope: In general, variables used within a
- function (other than the function's arguments) are
- bound to the function's local scope (there are
- ways to override this behavior). Variables bound
- to a function's local scope are not visible from a
- file's scope or from the global scope. They are
- created (undefined) when the function is invoked,
- and destroyed when the function returns.
-
- There are exceptions: variables used in a function
- context are bound to the global-symbol-table. For
- example:
-
- x = a * sin ( pi )
-
- `sin' is used in a function context, and is bound
- to the global scope, while `x', `a', and`pi' are
- bound to the function's local environment.
-
- Function's that are defined within a file have
- full access to the file's static variables.
- Function variables will be bound to the file's
- scope before local binding occurs. For example:
-
- ---- beginning of file.r ----
-
- static (A, pi)
- A = 1.e-3;
- pi = atan(1)*4;
-
- fun = function ( a ) { return A*sin(pi*A*a); }
-
- ---- end of file.r ----
-
- When `fun' is created it binds `A' and `pi'
- to file.r's static environment.
-
- There are two declarations: `global' and `local'
- that can be used to override the default behavior
- if necessary. Variables declared local will be
- bound to to the function's local scope, and
- variable declared global will be bound to the
- global scope.
-
- **NOTE: There is one more special exception (for
- advanced usage): Function variables can be
- members of a list, or members of a list, that is a
- member of another list, etc, etc... In effect this
- allows users to hide or protect variables and
- functions in an arbitrary manner. Thus, when RLaB
- sees something like:
-
- ML.e1.signal( a )
-
- it does not bind `ML' to the global scope. In this
- context RLaB cannot bind the function until
- runtime, so the list is by default bound to the
- function's local scope. This behavior can be
- changed by using the global, or static
- declarations.
-
-
- The built-in function fvscope performs a variable scope
- analysis of any user-function. For example:
-
- ---- beginning of file.r ----
- static (stat) // Keep track of some statistic.
- stat.n = 0;
- stat.total = 0;
-
- x = function (a, b)
- {
- local (a)
- global (pi)
-
- for( i in 1:a.nr )
- {
- a[;i] = a[;i]*norm(a);
- }
- retv = 2*pi*norm(a)*b;
- stat.n = stat.n + 1;
- stat.total = stat.total + retv;
-
- return << val = retv; avg = stat.total/stat.n >>;
- };
- ---- end of file.r ----
-
- > local ("./file.r");
- > fvscope(x);
- Function Variable SCOPE analysis for : x
- Filename: ./jnk.r
-
- line GLOBAL ARG LOCAL
-
- 10 Local-Var: i
- 10 Local-Var: a
- 12 Local-Var: a
- 12 Local-Var: i
- 12 Local-Var: a
- 12 Local-Var: i
- 12 Local-Var: a
- 12 Global-Var: norm
- 14 Local-Var: retv
- 14 Global-Var: pi*
- 14 Local-Var: a
- 14 Global-Var: norm
- 14 Arg-Var: b
- 15 Static-Var: stat
- 15 Static-Var: stat
- 16 Static-Var: stat
- 16 Static-Var: stat
- 16 Local-Var: retv
- 17 Local-Var: retv
- 17 Static-Var: stat
- 17 Static-Var: stat
-
- The function `x' is used to compute some arbitrary value. The
- list `stat' is used to keep track of how many times `x' is
- called, and to compute the average of the return
- value. fvscope shows us, line by line, each variable, and how
- it is bound.
-
- 3) Function arguments ------------------------------------------
-
- RLaB supports both "pass by reference" and "pass by value" for
- passing arguments to a function.
-
- Pass by reference means that the arguments, while still
- referred to be there declared names, are in fact bound to the
- caller's scope. Thus, the function can directly modify
- variables in the caller's scope.
-
- Pass by value means that a function cannot modify variables in
- the caller's scope - essentially, an argument that is passed
- by value is copied, and the copied value is passed to the
- function to operate on.
-
- Pass by reference can be considered the default behavior,
- since it takes no special effort on the user's part. Pass by
- value is achieved by declaring function arguments to be
- local. For example:
-
- // Pass by reference
-
- > myf = function ( A ) { A = "changed"; return A; }
- <user-function>
- > B=10;
- > myf(B);
- > B
- B =
- changed
-
- // Pass by value
- > myf = function ( A ) { local (A) A = "changed"; return A; }
- <user-function>
- > B=10;
- > myf(B);
- > B
- B =
- 10
-
- In the previous example B, a variable in the global workspace,
- is changed by myf (pass by reference). In the second part of
- the example, the function argument A, is redeclared to be
- local. This redeclaration forces the function argument to be
- passed by value.
-
- One advantage of this behavior is that users can create
- functions and selectively decide which variables should be
- passed by reference, and which should be passed by value.
-
- * * *
-
- You do not have to call a function with the same number of
- arguments specified in the definition. If you invoke a
- function with more arguments than declared, the result is an
- error. If you call the function with less arguments than
- declared, RLaB will pad the argument list with UNDEFINED,
- objects. Additionally, commas may be used to "skip" arguments
- that are unnecessary. for each argument that is "skipped" an
- UNDEFINED variable is passed to the function during execution.
-
- UNDEFINED arguments can be detected with the exist function,
- for example:
-
- if (!exist (ARG))
- {
- ARG = 0; // Initialize undefined argument
- }
-
- The function-local variable `nargs' is automatically
- initialized to the argument number of the last specified
- argument in the function call. For example:
-
- testf = function ( a, b, c, d, e )
- {
- nargin
- }
-
- > testf ( 1 , 2 );
- 2
- > testf ( 1 , , 2 );
- 3
- > testf ( 1 , , 2, 3 );
- 4
-
- * * *
-
- Lists can be used to get the effect of variable argument
- lists. If you are not familiar with lists, then now would be a
- good time to `help LIST'. A function can take a list as an
- argument and then pull the actual number of list elements, and
- their values, from the list when the function is called. For
- example:
-
- > vlistf = function( l )
- {
- local(i,x);
-
- printf( "number of elements in variable arg-list = %i\n", size(l) );
-
- // Pull each element from the list
-
- for( i in 1:size(l) )
- {
- x = l.[i];
- // now do something with x
- }
- };
- > vlistf( << "string"; [1,2;3,4] >> )
- number of elements in variable arg-list = 2
-
- * * *
-
- Functions can take other functions as arguments, for example:
-
- > trick = function ( a , b )
- {
- a(b)
- };
- > trick( eye, [3,3] );
- matrix columns 1 thru 3
- 1 0 0
- 0 1 0
- 0 0 1
-
- Note that the function name, passed as an argument, did not
- need quotes. This is so because functions are variables in the
- same sense as scalars, strings, and matrices. The variable a
- in the previous function example refers to the function eye,
- since function args are passed by reference.
-
- 4) Function return values --------------------------------------
-
- All functions return a value, although the return statement is
- optional. If a return statement is not used, then the function
- will return 0 (zero) to the calling environment. If the return
- statement is used, the result of the return statement is
- passed back to the calling environment.
-
- Functions can only return a single entity to the calling
- environment. If it is necessary to return more than one
- entity, a list can be used to group multiple entities together
- for return.
-
- Example:
-
- We want to write a function that creates a set of matrices (a
- state-space model). We will write such a function, and group
- the separate matrices together in a list.
-
- > ss = function( w )
- {
- local(A, B, n);
- n = size( w )[1];
- A = [ zeros(n,n), eye(n,n);
- -w; zeros(n,n) ];
- B = ones(n,n);
-
- return << A = A; B = B >>;
- };
- >
-
- The return statement creates the list, and assign the names
- `A' and `B' to it's members.
-
- Since functions are evaluated "in-place" their return values
- can be manipulated in the usual ways, for example:
-
- > eig(symm(rand(3,3))).val
- val =
- -0.937 0.571 1.81
-
- > eig(symm(rand(3,3))).val[2]
- 0.191
-
- > rand(10,10)[1,3,5;2,4,6]
- 0.29 0.411 0.345
- 0.561 0.686 0.0287
- 0.269 0.324 0.57
-
- 5) Function recursion ------------------------------------------
-
- Functions can call themselves recursively. For a function to
- call itself recursively, the special keyword `$self' must be
- used. `$self' must be used because the statements within a
- function are compiled before the function is assigned to a
- variable. Therefore, the function cannot resolve a recursive
- reference without `$self'.
-
- Example:
-
- > fact = function (f)
- {
- if(f <= 1) {
- return 1;
- else
- return f*$self(f-1);
- }
- };
- > fact(10)
- 3628800
-
- The local statement in the previous function makes `a' local
- to the function `x'. Since `a' is also a function argument, it
- is copied into the local variable `a', which is used for the
- throughout the function. As you can see `a' does not even show
- up as an argument variable in the output from fvscope.
-
- Since `i' is not explicitly declared, it defaults to a local
- variable with initial value undefined. When the function
- returns the variable `i' (and all other local variables) will
- cease to exist. When x() is called again `i' (and all other
- local variables) will again be re-initialized undefined. The
- local statement must be the 1st statement in a function, and
- only one local statement is allowed. If you must declare alot
- of local variables, then break the local statement with a
- continuation. Note that `norm', although undeclared, is a
- global variable. This is because `norm' is a function. Since
- functions cannot be entirely local to another function it
- makes no sense to have to declare all functions global.
-
- The global statement tells the function to get `pi' from the
- global workspace. The global statement must follow the local
- statement, and precede any executable function statements.
-
- 6) Special Topics ----------------------------------------------
-
- A) Although pass by reference is the default behavior
- for function arguments, there are some instances where
- this may not seem true (but it is). For example, when
- you pass part of a matrix into a function you cannot
- modify the original matrix.
-
- > x = function ( a ) { global (pi) a[1] = pi; }
- <user-function>
- > z=rand(2,2);
- > z
- z =
- 0.0369 0.665
- 0.162 0.0847
- > x(z);
- > z
- z =
- 3.14 0.665
- 0.162 0.0847
- > x(z[2]);
- > z
- z =
- 3.14 0.665
- 0.162 0.0847
- > y
- UNDEFINED
- > x(y=z[2]);
- > y
- y =
- 3.14
-
- You can see that in the first function call, z is
- passed by reference. In the second call, the second
- element of z (z[2]) is copied into a temporary
- variable, which in turn is passed by reference to the
- function. In the last call the temporary variable is
- stored in the variable y, which as you can see, is
- passed by reference to the function for modification.
-
- ----------------------------------------------------------------
-